//go:build v1

package queue

import (
	"context"
	"sync"
)

// 有问题的版本

type ConcurrentBlockingQueue[T any] struct {
	data  []T
	mutex *sync.Mutex
	//这种方案是不行的，一旦Cond 调用wait就会一直阻塞 无法知道是否超时
	// notfullCond  *sync.Cond
	// notemptyCond *sync.Cond
	notfull  chan struct{}
	notempty chan struct{}
	maxSize  int
}

func NewConcurrentBlockingQueue[T any](maxsize int) *ConcurrentBlockingQueue[T] {
	c := &sync.Mutex{}
	return &ConcurrentBlockingQueue[T]{
		data:     make([]T, 0, maxsize),
		mutex:    c,
		notfull:  make(chan struct{}, 1),
		notempty: make(chan struct{}, 1),
		// notfull:  sync.NewCond(c),
		// notempty: sync.NewCond(c),
		maxSize: maxsize,
	}
}

func (c *ConcurrentBlockingQueue[T]) EnQueue(ctx context.Context, data T) error {
	if ctx.Err() != nil {
		return ctx.Err()
	}
	c.mutex.Lock()

	//控制住了超时
	for c.IsFull() { //不能使用if
		// c.notfull.Wait()
		c.mutex.Unlock()
		select {
		case <-c.notfull:
			c.mutex.Lock()
		case <-ctx.Done():
			return ctx.Err()
		}
	}
	c.data = append(c.data, data)
	if len(c.data) == 1 {
		// 并发的时候  这个地方会有问题  会漏发信号
		c.notempty <- struct{}{}
	}

	c.mutex.Unlock()
	return nil
}
func (c *ConcurrentBlockingQueue[T]) DeQueue(ctx context.Context) (T, error) {
	var t T
	if ctx.Err() != nil {
		return t, ctx.Err()
	}
	c.mutex.Lock()
	// defer c.mutex.Unlock()
	for c.IsEmpty() {
		// c.notempty.Wait()
		c.mutex.Unlock()
		select {
		case <-c.notempty:
			c.mutex.Lock()
		case <-ctx.Done():
			return t, ctx.Err()
		}
	}

	t = c.data[0]
	c.data = c.data[1:]

	if len(c.data) == c.maxSize-1 {
		c.notfull <- struct{}{}
	}

	c.mutex.Unlock()
	return t, nil
}
func (c *ConcurrentBlockingQueue[T]) Len() uint64 {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return uint64(len(c.data))
}
func (c *ConcurrentBlockingQueue[T]) IsEmpty() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return len(c.data) == 0
}
func (c *ConcurrentBlockingQueue[T]) IsFull() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return len(c.data) == c.maxSize
}
